#pragma once

#include "Thread.h"
#include "TimeValue.h" // for default param
#include "RoomMessage.h"
#include "SimpleEvent.h"
#include "SimpleCriticalSection.h"
#include "SimpleWaitableTimer.h"

namespace RoomFW {

struct IActiveObject;

//
// Class:	RoomTimer
//
// Description:	Simple Timer implementation.
//
// Author:	Andrew Sage
//
// Notes
//
// Initial testing on windows indicates a maximum resolution of 15 milliseconds.
//
class RoomTimer
{
public:

	//
	// Timer ID type.
	//
	typedef MessageID TimerId;

	//
	// Invalid timer id.
	//
	static const TimerId InvalidTimerId = 0;

	//
	// Timer id Manager.  Must be shared by all timers for an active object.
	//
	class IdMgr
	{
	public:
		class IdMgrId
		{
		public:
			IdMgrId(TimerId id, IdMgr* mgr);
			~IdMgrId();
			operator TimerId();
		private:
			TimerId id_;
			IdMgr* mgr_;
		};
		typedef ::boost::shared_ptr<IdMgrId> TimerIdPtr;
		friend class IdMgrId;
		IdMgr();
		~IdMgr();
		TimerIdPtr next();
	private:
		void release(TimerId timerId);
		TimerId nextId_;
		std::set<TimerId> inUse_;
		SimpleCriticalSection cs_;
	};

	//
	// Method:	RoomTimer
	//
	// Description:	Constructor
	//
	// Parameters:	None
	//
	RoomTimer(IdMgr* idMgr);

	//
	// Method:	~RoomTimer
	//
	// Description:	Destructor
	//
	virtual ~RoomTimer();

	//
	// Method:	initialize
	//
	// Description:	Initialize the object.  Must be called before use.
	//
	// Parameters:
	//
	//	maxSize - Specifies max number off handles added by addHandles().
	//
	// Return:	Success.
	//
	bool initialize(size_t maxSize);

	//
	// Method:	setTimer
	//
	// Description:	Set a timer.  When the timer expires, handler->put(expirationMessage)
	//
	// Parameters:
	//
	//	handler - Active object that will recieve the expiration message.
	//
	//	expirationMessage - Message generated by expiration.
	//
	//	expireIn - Time until first expiration.  See class notes for resolution.
	//
	//	repeatEvery - Interval to continue expiring.  See class notes for resolution.
	//					If 0, the timer does not repeat.
	//
	// Return:	Timer Id.  Needed to cancel the timer.
	//
	TimerId setTimer(IActiveObject* handler,
					 RoomMessageSP expirationMessage,
					 const TimeValue& expireIn,
					 const TimeValue& repeatEvery = 0);

	//
	// Method:	cancelTimer
	//
	// Description:	Cancel a timer.
	//
	// Parameters:
	//
	//	timerId - Timer id returned by setTimer().
	//
	// Return:	Success.
	//
	bool cancelTimer(TimerId timerId);

	//
	// Method:	full
	//
	// Description:	Test if no more timers can be created.
	//
	// Parameters:	None.
	//
	// Return:	True if no more timers can be created.
	//
	bool full();

	//
	// Method:	Size
	//
	// Description:	Return number of timers set.
	//
	// Parameters:	None.
	//
	// Return:	Number of timers set.
	//
	size_t size();

	//
	// Method:	addHandles
	//
	// Description:	Add timer handles to array.
	//
	// Parameters:	HandleArray to add to.
	//
	// Return:	None.
	//
	void addHandles(HandleArray& handles);

	//
	// Method:	signal
	//
	// Description:	Handle signaling of the specified timer handle.
	//
	// Parameters:	Handle of timer signaled.
	//
	// Return:	None.
	//
	void signal(HANDLE handle);

	//
	// Method:	pulse
	//
	// Description:	Check all timers without waiting and process any that are expired.
	//
	// Parameters:	None
	//
	// Return:	None.
	//
	void pulse();

protected:

private:

	//
	// Shared Id Manager.
	//
	IdMgr* idMgr_;

	//
	// Maximum number of timers.
	//
	size_t maxSize_;

	//
	// Timer Data.
	//
	struct TimerData
	{
		IdMgr::TimerIdPtr timerId;
		SimpleWaitableTimer timer;
		bool repeat;
		bool cancel;
		IActiveObject* handler;
		RoomMessageSP expirationMessage;
	};
	typedef std::list<TimerData> TimerDataList;
	typedef std::map<TimerId, TimerDataList::iterator> TimerIdMap;
	typedef std::map<HANDLE, TimerDataList::iterator> TimerHandleMap;

	//
	// Timers set for this object.
	//
	TimerDataList timerData_;

	//
	// Fast timer data lookup.
	//
	TimerIdMap timerMap_;
	TimerHandleMap handleMap_;

	//
	// Synchronize access to timer data.
	//
	SimpleCriticalSection cs_;

	//
	// Timer data set event.
	//
	SimpleEvent setEvent_;

	//
	// Not designed to be copied.
	//
	RoomTimer(const RoomTimer&);
	RoomTimer& operator =(const RoomTimer&);
};

}
